#include "NodeVisitor.h"

using namespace std;

/*
 * Tree restructuring to make processing easier
 */

void ReachabilityTreeRestucturer::visit(LocalVariableDeclarationNode*n) {

	if ("Statement" != n->parent->Type()) {
		StatementNode* newParent = new StatementNode();
		newParent->parent = n->parent;
		newParent->children.push_back(n);
		n->ReplaceMeWith(newParent);
		n->parent = newParent;
	}
}

void ReachabilityTreeRestucturer::visitAddLiteralParent(ParentNode*n) {
	if ("Literal" != n->parent->Type()) {
		LiteralNode* newParent = new LiteralNode();
		newParent->parent = n->parent;
		newParent->children.push_back(n);
		n->ReplaceMeWith(newParent);
		n->parent = newParent;
	}
}


/*
 * METHOD BODY EVALUATION
 */

void ReachabilityVisitor::visit(ConstructorDeclarationNode* n) {
	if (error) return;
	StatementInOut inner_eval(MAYBE);
	n->Accept(&inner_eval);
	if (inner_eval.error) {
		error = true;
		return;
	}
}

void ReachabilityVisitor::visit(MethodDeclarationNode* n) {
	if (error) return;
	if (n->modifier & ModifiedNode::Native || n->modifier & ModifiedNode::Abstract) return;
	StatementInOut inner_eval (MAYBE);
	n->Accept(&inner_eval);
	if (inner_eval.error) {
		error = true;
		return;
	}
	// non-void methods error when out is not NO
	if (TypeMeta::Void != n->type_meta.category) {
		if (NO != inner_eval.out) {
			error = true;
		}
	}
}

/*
 * STATEMENT EVALUATION
 */

void StatementInOut::visit(StatementNode* n) {
	if (error || processed) return;
	processed = true;
	// Process inner statments
	StatementInOut inner_eval(in);
	n->children[0]()->Accept(&inner_eval);
	if (inner_eval.error) {
		error = true;
		return;
	}
	out = inner_eval.out;
}

void StatementInOut::visit(ReturnStatementNode* n) {
	if (error || processed) return;
	processed = true;
	out = NO;
}

void StatementInOut::visit(BlockNode* n) {
	if (error || processed) return;
	processed = true;

	//sequentially process each statement in a block
	// the in of the next statement is the out of the previous
	bool curIn = in;
	for (vector<SP<ParseNode> >::iterator it = n->children.begin(); it != n->children.end(); ++it ) {
		StatementInOut inner_eval(curIn);
		(*it)()->Accept(&inner_eval);

		if (inner_eval.error) {
			error = true;
			return;
		}
		curIn = inner_eval.out;
	}
	out = curIn;
}

void StatementInOut::visit(IfStatementNode* n) {
	n->DeleteLeafs();
	if (error || processed) return;
	processed = true;

	// We only have to make sure that all nested statements are valid in this case
	for (vector<SP<ParseNode> >::iterator it = n->children.begin();
				it != n->children.end(); ++it) {
		if ("Statement" != (*it)()->Type()) {
			continue;	// skip over expression nodes
		}

		StatementInOut inner_eval(in);
		(*it)()->Accept(&inner_eval);

		if (inner_eval.error) {
			error = true;
			return;
		}
	}

}

void StatementInOut::visit(IfThenElseStatementNode* n) {
	n->DeleteLeafs();
	if (error || processed) return;
	processed = true;

	out = NO;
	// We only have to make sure that all nested statements are valid in this case
	for (vector<SP<ParseNode> >::iterator it = n->children.begin();
		it != n->children.end(); ++it) {
		if ("Statement" != (*it)()->Type()) {
			continue;	// skip over expression nodes
		}

		StatementInOut inner_eval(in);
		(*it)()->Accept(&inner_eval);

		if (inner_eval.error) {
			error = true;
			return;
		}
		out = out || inner_eval.out;
	}
}

void StatementInOut::visit(WhileStatementNode* n) {
	n->DeleteLeafs();
	if (error || processed) return;
	processed = true;
	// check if literal in while expression, ie true / false while loop
	ExpressionNode* whileCond = (ExpressionNode*)n->children[0]();
	if (whileCond->children.size() ==  1 && "Literal" == whileCond->children[0]()->Type() ) {
		BooleanLiteralNode* litval = (BooleanLiteralNode*)((ParentNode*)whileCond->children[0]())->children[0]();
		if (!litval->value) {
			// false loop, error
			error = true;
			return;
		}
		// true loop
		out = NO;
	}
	// Process the statement for reachability
	StatementInOut inner_eval(in);
	n->children[1]()->Accept(&inner_eval);
	if (inner_eval.error) {
		error = true;
		return;
	}
}


void StatementInOut::visit(ForStatementNode *n) {
	n->DeleteLeafs();
	if (error || processed) return;
	processed = true;
	// check if literal in case of
	bool usingTrueCond = false, usingNoCond = true;

	ExpressionNode* forCond = (ExpressionNode*)(*n)["Expression"];
	if (forCond) {
		usingNoCond = false;
		if ("Literal" == ((ParentNode*)forCond->children[0]())->Type())
		{
			BooleanLiteralNode* litval = (BooleanLiteralNode*)((ParentNode*)forCond->children[0]())->children[0]();
			if (!litval->value) {
				// false loop, error
				error = true;
				return;
			}
			usingTrueCond = true;
		}
	}
	
	if (usingTrueCond || usingNoCond) {
		out = NO;
	}

	StatementNode* s = (StatementNode*)(*n)["Statement"];
	StatementInOut inner_eval(in);
	if (inner_eval.error) {
		error = true;
		return;
	}
	if (!s) return;
	s->Accept(&inner_eval);
	if (inner_eval.error) {
		error = true;
		return;
	}
}